#include "MulticastReceiver.h"

MulticastReceiver::MulticastReceiver(char *localIp, int recvPort, char *multiIpAddr) 
{
    int reuse = 1;
    int ifnameLen = -1;
    char ifname[64];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if(sockfd == -1)
    {
        printf("socket error\r\n");
        return;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) == -1) 
    {
        printf("setsockopt():SO_REUSEPORT error\r\n");
        close(sockfd);
        return;
    }

    // 绑定iP和端口
    struct sockaddr_in client;
    memset(&client, 0, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons(recvPort); // ........ 
    inet_pton(AF_INET, "0.0.0.0", &client.sin_addr.s_addr);
    int ret  = bind(sockfd, (struct sockaddr*)&client, sizeof(client));
    if(ret == -1)
    {
        printf("bind error\r\n");
        close(sockfd);
        return;
    }
 
    int loop = 0;
    int err = setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
    if(err < 0)
    {
        printf("setsockopt():IP_MULTICAST_LOOP error\r\n");
        close(sockfd);
        return;
    }

    memset(ifname, 0, sizeof(ifname));
    ifnameLen = GetIfnameByIp(localIp, ifname, sizeof(ifname));
    if(ifnameLen == -1)
    {
        printf("can not get ifname %s\r\n", localIp);
        close(sockfd);
        return;
    }

    struct ip_mreqn fl;
    inet_pton(AF_INET, multiIpAddr, &fl.imr_multiaddr.s_addr);
    inet_pton(AF_INET, "0.0.0.0", &fl.imr_address.s_addr);
    fl.imr_ifindex = if_nametoindex(ifname);
    setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &fl, sizeof(fl));
    if(ret < 0)
    {
        printf("setsockopt():IP_ADD_MEMBERSHIP error\r\n");
        close(sockfd);
        return;
    }

    isNormal = true;
}

MulticastReceiver::~MulticastReceiver() 
{
    if(sockfd != -1)
        close(sockfd);
}

int MulticastReceiver::Recv(char *buffer, int len)
{
    int ret = -1;
    
    if(isNormal)
    {
        ret = recvfrom(sockfd, buffer, len, 0, NULL, NULL);
    }
    else
    {
        printf("init failed\r\n");
    }
    
    return ret;
}

int MulticastReceiver::GetIfnameByIp(char *ip, char *ifname, int ifnameLen)
{
    int ret = -1;
    struct ifconf ifconf;
    struct ifreq *ifreq;
    char buf[512];//缓冲区

    if(sockfd == -1)
    {
        return -1;
    }

    //初始化ifconf
    ifconf.ifc_len =512;
    ifconf.ifc_buf = buf;
    
    ioctl(sockfd, SIOCGIFCONF, &ifconf); //获取全部接口信息

    //接下来一个一个的获取IP地址
    ifreq = (struct ifreq*)ifconf.ifc_buf;
    //printf("ifconf.ifc_len:%d\n",ifconf.ifc_len);
    //printf("sizeof (struct ifreq):%d\n",sizeof (struct ifreq));

    for (int i=(ifconf.ifc_len/sizeof (struct ifreq)); i>0; i--)
    {
        if(ifreq->ifr_flags == AF_INET)//for ipv4
        { 
            //printf("name =[%s]\n" , ifreq->ifr_name);
            //printf("local addr = [%s]\n" ,inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));
            if(strncmp(inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr), ip, strlen(ip)) == 0)
            {
                strncpy(ifname, ifreq->ifr_name, ifnameLen);
                ret = strlen(ifreq->ifr_name);
                printf("use ifname = %s, ip = %s\r\n", ifname, ip);
                break;
            }
            ifreq++;
        }
    }

    return ret;
}
